const isObject = val => val !== null && typeof val === 'object'
const convert = target => isObject(target) ? reactive(target) : target
const hasOwnProperty = Object.prototype.hasOwnProperty
const hasOwn = (target, key) => hasOwnProperty.call(target, key)

export function reactive (target) {
  // 判断是否是对象
  if (!isObject(target)) return target
  // handler=> {get, set, deleteProperty} get中收集依赖
  const handler = {
    get (target, key, receiver) {
      // 依赖收集
      track(target, key)
      const result = Reflect.get(target, key, receiver)
      return convert(result)
    },
    set (target, key, receiver) {
      const oldValue = Reflect.get(target, key, receiver)
      let result = true
      if (oldValue !== target) {
        result = Reflect.set(target, key, receiver)
        // todo 触发更新
        trigger(target, key)
      }
      return result
    },
    deleteProperty (target, key) {
      const hasKey = hasOwn(target, key)
      const result = Reflect.deleteProperty(target, key)
      if (hasKey && result) {
        // todo 触发更新
        trigger(target, key)
      }
      return result
    }
  }
  // retrun new Proxy
  return new Proxy(target, handler)
}

// ref
export function ref (raw) {
  //判断raw是否是由ref创建的对象，如果是就直接返回

  // 使用convert函数判断raw是否是对象，如果是直接用reactive处理，不是继续使用ref逻辑处理
  let value = convert(raw)
  let r = {
    __v_isRef: true,
    get value () {
      // 触发依赖收集
      track(r, 'value')
      return value
    },
    set value (newValue) {
      if (newValue !== value) {
        raw = newValue
        value = convert(raw)
        // 触发更新
        trigger(r, 'value')
      }

    }
  }
  return r
}

// toRefs
export function toRefs (proxy) {
  // 判断参时是否是数据 ？ 是
}

let activesEffect = null
export function effect (callback) {
  activesEffect = callback
  callback() // callback 运行时如果有响应数据会触发get，在get中运行了track，触发了依赖收集
  // todo
  activesEffect = null
}
// 收集依赖
let targetMap = new WeakMap()
function track (target, key) {
  // 判断activesRffect是否存在, 不存在直接return
  if (!activesEffect) return
  // 获取去targetMap中的depsMap 如果没有值就在targetMap新创建一个depsMap
  let depsMap = targetMap.get(target)
  if (!depsMap) {
    targetMap.set(target, (depsMap = new Map()))
  }
  // 根据属性获取depsMap中的dep， 如果没有就创建一个dep => dep中储存的是effect方法集合
  let dep = depsMap.get(key)
  if (!dep){
    depsMap.set(key, (dep = new Set()))
  }
  // 把effect函数添加到dep中
  dep.add(activesEffect)
  console.log(targetMap)
}

function trigger (target, key) {
  // 去targetMap中寻找depsMap，没找到直接返回
  const depsMap = targetMap.get(target)
  if (!depsMap) return
  // 去depsMap寻找dep， 找到遍历执行
  const dep = depsMap.get(key)
  if (dep) {
    dep.forEach(element => {
      element()
    })
  }
}